/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
 *
 */

import log4js, { levels } from 'log4js';
import path from 'path';
import { parentPort, workerData } from 'worker_threads';

import { HvigorLoggerConfig } from '@ohos/hvigor-logger';

import { HvigorConfigLoader } from '../../../../common/util/hvigor-config-loader.js';
import { getConfiguration, levelMap, setCategoriesLevel } from '../../../log/default-configuration.js';
import { HvigorLogger } from '../../../log/hvigor-log.js';
import { PoolConstant } from '../constant/constant.js';
import { CacheStoreManager } from '../store/cache-store.js';
import { ExtendedErrorInfo } from './extended-error-info.js';

setCategoriesLevel(levelMap.get(workerData.logLevel) ?? levels.INFO);
HvigorLoggerConfig.setCategoriesLevel(levelMap.get(workerData.logLevel) ?? levels.INFO);
log4js.shutdown();
log4js.configure(getConfiguration());

let workerCacheManager: CacheStoreManager | undefined;
if (workerData.shouldResident) {
  workerCacheManager = new CacheStoreManager({
    capacity: workerData.cacheCapacity,
    ttl: workerData.cacheTtl,
  });
}

/**
 * 子线程监听父线程传递的数据，并根据收到的数据执行工作
 */
parentPort!.on('message', async (work) => {
  if (work.event === PoolConstant.CLEAN_HVIGOR_CONFIG_LOADER) {
    HvigorConfigLoader.clean();
    return;
  }
  if (work.event === PoolConstant.CLEAN_HVIGOR_LOGGER) {
    HvigorLogger.clean();
    return;
  }
  if (work.event === PoolConstant.UNMOUNT_TSC_COMMON_CACHE_EVENT) {
    unmountTscCommonCache();
    return;
  }
  const onExit = (exitCode: number) => {
    if (exitCode !== 0) {
      throw new Error(`A process.exit was called in worker thread with exit code ${exitCode}`);
    }
  };
  process.on('exit', onExit);
  let fn;
  const workPath: string = work.workPath;
  const inputData: unknown = work.inputData;
  if (workPath.indexOf(PoolConstant.FILE_SUFFIX) > 0) {
    const splitLoc: number = workPath.indexOf(PoolConstant.FILE_SUFFIX) + PoolConstant.FILE_SUFFIX.length;
    const fileName: string = workPath.slice(0, splitLoc);
    const subPaths: string[] = workPath.slice(splitLoc + 1).split(path.sep);
    let fileOutput = await import(fileName);
    if (!subPaths.length || subPaths[0] === '') {
      fn = fileOutput.default;
    } else {
      for (let i = 0; i < subPaths.length; i++) {
        const subPath = subPaths[i];
        if (subPath !== '') {
          fileOutput = fileOutput[subPath];
          continue;
        }
        if (i === subPaths.length - 1) {
          fileOutput = fileOutput.default;
          break;
        } else {
          parentPort!.postMessage({ event: PoolConstant.WORK_ERROR, id: work.id });
          return;
        }
      }
      fn = fileOutput;
    }
  }
  const startTime = Number(process.hrtime.bigint());
  const retVal = await fn(inputData, workerCacheManager);
  const endTime = Number(process.hrtime.bigint());

  // 在work结束后,发送消息给主进程,通知该work执行完成,执行过程中如果抛出异常,直接在主进程中处理和捕获
  parentPort!.postMessage(getReturnMessage(retVal, work.id, startTime, endTime));
  process.off('exit', onExit);
  if (work.exitAfterDone) {
    process.exit(0);
  }
});

function unmountTscCommonCache() {
  workerCacheManager?.unmount(PoolConstant.TSC_COMMON_CACHE_KEY);
}

function getReturnMessage(retVal: any, id: number, startTime: number, endTime: number) {
  const cacheSize = workerCacheManager?.cacheItemSize();
  if (retVal instanceof Error) {
    return {
      event: PoolConstant.WORK_ERROR,
      id: id,
      returnVal: {
        name: retVal.name,
        message: retVal.message,
        stack: retVal.stack,
        extraInfo: (retVal as ExtendedErrorInfo).extraInfo
      },
      cacheSize: cacheSize,
      startTime,
      endTime,
    };
  }
  return { event: PoolConstant.WORK_DONE, id: id, returnVal: retVal, cacheSize: cacheSize, startTime, endTime };
}

for (const preludeDep of workerData.preludeDeps) {
  require(preludeDep);
}
